using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;

using BlogEngine.Core.Providers;

namespace BlogEngine.Core
{
	/// <summary>
	/// Categories are a way to organize posts. 
	/// A post can be in multiple categories.
	/// </summary>
	[Serializable, DataObject]
	public class Term : BusinessBase<Term, int>
	{
		private string _name;
		private string _slug;
		private TermType _type;
	
		#region Constructor

		/// <summary>
		/// Initializes a new instance of the <see cref="Term"/> class.
		/// </summary>
		public Term() 
			: this(String.Empty, string.Empty) { }

		/// <summary>
		/// Initializes a new instance of the <see cref="Term"/> class.
		/// </summary>
		/// <param name="name">The name.</param>
		/// <param name="slug">The slug.</param>
		public Term(string name, string slug)
			: this(name, slug, TermType.Category) { }

		/// <summary>
		/// Initializes a new instance of the <see cref="Term"/> class.
		/// </summary>
		/// <param name="name">The name.</param>
		/// <param name="slug">The slug.</param>
		/// <param name="type">The type.</param>
		public Term(string name, string slug, TermType type)
		{
			_name = name;
			_slug = slug;
			_type = type;
		}

		#endregion

		#region Properties

		/// <summary>
		/// Gets or sets the Title or the object.
		/// </summary>
		public string Name
		{
			get { return _name; }
			set
			{
				if (_name != value) 
					OnPropertyChanged("Title");
				
				_name = value;

				if (Slug == null)
					Slug = Utils.RemoveIllegalCharacters(_name);
			}
		}

		/// <summary>
		/// Gets the slug.
		/// </summary>
		/// <value>The slug.</value>
		public string Slug
		{
			get { return _slug; }
			set
			{
				value = Utils.RemoveIllegalCharacters(value);

				if (_slug != value)
					OnPropertyChanged("Slug");

				_slug = value;
			}
		}

		/// <summary>
		/// Gets or sets the type.
		/// </summary>
		/// <value>The type.</value>
		public TermType Type
		{
			get { return _type; }
			set
			{
				if (_type != value)
					OnPropertyChanged("Type");

				_type = value;
			}
		}

		/// <summary>
		/// Gets or sets the post count.
		/// </summary>
		/// <value>The post count.</value>
		public int TotalPosts { get; internal set; }

		#endregion

		#region Methods

		/// <summary>
		/// Returns a category based on the specified id.
		/// </summary>
		[DataObjectMethod(DataObjectMethodType.Select)]
		public static Term GetTerm(TermType type, string slug)
		{
			return BlogService.SelectTerm(type, slug);
		}

		/// <summary>
		/// Returns a category based on the specified id.
		/// </summary>
		[DataObjectMethod(DataObjectMethodType.Select)]
		public static List<Term> GetTerms(TermType type)
		{
			switch (type)
			{
				case TermType.Category: return Categories;
				case TermType.Tag: return Tags;
				default: goto case TermType.Category;
			}
		}

		private static object _SyncRoot = new object();
		private static List<Term> _terms;
		/// <summary>
		/// Gets an unsorted list of all Categories.
		/// </summary>
		public static List<Term> Terms
		{
			get
			{
				if (_terms == null)
				{
					lock (_SyncRoot)
					{
						if (_terms == null)
							_terms = BlogService.SelectTerms();
					}
				}

				return _terms;
			}
		}

		/// <summary>
		/// Gets the categories.
		/// </summary>
		/// <value>The categories.</value>
		public static List<Term> Categories
		{
			get
			{
				return Terms.FindAll(delegate(Term obj)
				{
					return obj.Type == TermType.Category;
				});
			}
		}

		/// <summary>
		/// Gets the tags.
		/// </summary>
		/// <value>The tags.</value>
		public static List<Term> Tags
		{
			get
			{
				return Terms.FindAll(delegate(Term obj)
				{
					return obj.Type == TermType.Tag;
				});
			}
		}

		#region Transition Properties

		public string Title
		{
			get { return Name; }
		}

		public string Description
		{
			get { return String.Empty; }
		}

		#endregion

		#endregion

		#region Base overrides

		/// <summary>
		/// Reinforces the business rules by adding additional rules to the
		/// broken rules collection.
		/// </summary>
		protected override void Validate()
		{
			AddError(String.IsNullOrEmpty(Name), "Title", "Title must be set.");
		}

		/// <summary>
		/// Retrieves the object from the data store and populates it.
		/// </summary>
		/// <param name="id">The unique identifier of the object.</param>
		/// <returns>
		/// True if the object exists and is being populated successfully
		/// </returns>
		protected override Term DataSelect(int id)
		{
			return null;
		}

		/// <summary>
		/// Updates the object in its data store.
		/// </summary>
		protected override void DataUpdate()
		{
		}

		/// <summary>
		/// Inserts a new object to the data store.
		/// </summary>
		protected override void DataInsert()
		{
		}

		/// <summary>
		/// Deletes the object from the data store.
		/// </summary>
		protected override void DataDelete()
		{
		}

		/// <summary>
		/// Saves the object to the database.
		/// </summary>
		public override void AcceptChanges()
		{
		}

		/// <summary>
		/// Returns a <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
		/// </summary>
		/// <returns>
		/// A <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
		/// </returns>
		public override string ToString()
		{
			return Name;
		}

		#endregion

		/// <summary>
		/// Performs an implicit conversion from <see cref="BlogEngine.Core.Term"/> to <see cref="System.String"/>.
		/// </summary>
		/// <param name="term">The term.</param>
		/// <returns>The result of the conversion.</returns>
		public static implicit operator string(Term term)
		{
			if (term == null)
				return null;

			return term.Name;
		}
	}
}
